#include <iostream>
#include <string>
#include <stdio.h>
#include <stdexcept> // 为了使用标准异常类

enum class IOS
{
    OPEN,
    NOT_OPEN
};

class File
{
public:
    File()
        : m_fp(nullptr), m_flag(IOS::NOT_OPEN)
    {
    }

    File(const std::string &filename, const std::string &mode)
    {
        m_fp = fopen(filename.c_str(), mode.c_str());
        if (m_fp == nullptr)
        {
            m_flag = IOS::NOT_OPEN;
            throw std::runtime_error("open file error!");
        }
        m_flag = IOS::OPEN;
        m_file = filename;
    }

    // 深拷贝构造函数
    File(const File &other)
    {
        m_file = other.m_file;
        m_flag = other.m_flag;

        if (other.m_fp)
        {
            m_fp = fopen(m_file.c_str(), "r+");
            if (m_fp == nullptr)
            {
                m_flag = IOS::NOT_OPEN;
                throw std::runtime_error("open file error!");
            }
        }
        else
        {
            m_fp = nullptr;
        }
    }

    // 移动构造函数
    File(File &&other) noexcept
    {
        m_file = std::move(other.m_file);
        m_fp = other.m_fp;
        m_flag = other.m_flag;

        other.m_fp = nullptr;
        other.m_flag = IOS::NOT_OPEN;
    }

    ~File()
    {
        if (m_fp)
        {
            fclose(m_fp);
        }
    }

    // 重载赋值运算符
    File &operator=(const File &other)
    {
        if (this == &other)
            return *this;

        if (m_fp)
        {
            fclose(m_fp);
        }

        m_file = other.m_file;
        m_flag = other.m_flag;

        if (other.m_fp)
        {
            m_fp = fopen(m_file.c_str(), "r+");
            if (m_fp == nullptr)
            {
                m_flag = IOS::NOT_OPEN;
                throw std::runtime_error("open file error!");
            }
        }
        else
        {
            m_fp = nullptr;
        }

        return *this;
    }

    // 重载移动赋值运算符
    File &operator=(File &&other) noexcept
    {
        if (this == &other)
            return *this;

        if (m_fp)
        {
            fclose(m_fp);
        }

        m_file = std::move(other.m_file);
        m_fp = other.m_fp;
        m_flag = other.m_flag;

        other.m_fp = nullptr;
        other.m_flag = IOS::NOT_OPEN;

        return *this;
    }

    void OpenFile(const std::string &filename, const std::string &mode)
    {
        if (m_fp)
        {
            fclose(m_fp);
        }

        m_fp = fopen(filename.c_str(), mode.c_str());
        if (m_fp == nullptr)
        {
            m_flag = IOS::NOT_OPEN;
            throw std::runtime_error("open file error!");
        }
        m_file = filename;
        m_flag = IOS::OPEN;
    }

    char get_char()
    {
        if (m_flag == IOS::OPEN)
        {
            return fgetc(m_fp);
        }
        else
        {
            throw std::runtime_error("file is not open!\n");
        }
    }

    std::string get_line()
    {
        if (m_flag == IOS::OPEN)
        {
            char buffer[256];
            if (fgets(buffer, sizeof(buffer), m_fp) != nullptr)
            {
                return std::string(buffer);
            }
        }
        else
        {
            throw std::runtime_error("file is not open!\n");
        }
        return "";
    }

    std::string get_all() const
    {
        std::string content;
        if (m_flag == IOS::OPEN)
        {
            long current_pos = ftell(m_fp);
            fseek(m_fp, 0, SEEK_SET);
            char buffer[256];
            while (fgets(buffer, sizeof(buffer), m_fp) != nullptr)
            {
                content += buffer;
            }
            fseek(m_fp, current_pos, SEEK_SET); // 恢复文件指针位置
        }
        else
        {
            throw std::runtime_error("file is not open!\n");
        }
        return content;
    }

    template <typename U>
    U get_bin()
    {
        U temp;
        if (m_flag == IOS::OPEN)
        {
            fread(&temp, sizeof(U), 1, m_fp);
        }
        else
        {
            throw std::runtime_error("file is not open!\n");
        }
        return temp;
    }

    void write_data(const std::string &data)
    {
        if (m_flag == IOS::OPEN)
        {
            fwrite(data.c_str(), sizeof(char), data.size(), m_fp);
        }
        else
        {
            throw std::runtime_error("file is not open!\n");
        }
    }

    template <typename T>
    void write_bin(const T &data)
    {
        if (m_flag == IOS::OPEN)
        {
            fwrite(&data, sizeof(T), 1, m_fp);
        }
        else
        {
            throw std::runtime_error("file is not open!\n");
        }
    }

    void seek(long offset, int whence = SEEK_SET)
    {
        if (m_flag == IOS::OPEN)
        {
            fseek(m_fp, offset, whence);
        }
        else
        {
            throw std::runtime_error("file is not open!\n");
        }
    }

    void copy(const File &file)
    {
        if (m_flag == IOS::OPEN && file.m_flag == IOS::OPEN)
        {
            std::string data = file.get_all();
            write_data(data);
        }
        else
        {
            throw std::runtime_error("file is not open!\n");
        }
    }

    bool operator!() const
    {
        return m_flag == IOS::NOT_OPEN;
    }

    // 重载小于运算符
    bool operator<(const File &other) const
    {
        return m_file < other.m_file;
    }

    // 重载加号运算符
    File operator+(const File &other) const
    {
        File newFile;
        if (this->m_flag == IOS::OPEN && other.m_flag == IOS::OPEN)
        {
            newFile.OpenFile("merged_file.txt", "w+");
            newFile.write_data(this->get_all());
            newFile.write_data(other.get_all());
        }
        return newFile;
    }

private:
    std::string m_file;
    mutable FILE *m_fp; // 将m_fp设置为mutable以允许const成员函数修改
    IOS m_flag;
};

int main(int argc, char **argv)
{
    try
    {
        File file1("a.txt", "w+");
        file1.write_data("hello");

        File file2("b.txt", "w+");
        file2.write_data(" world!");
        /* 重载加号 */
        File mergedFile = file1 + file2;
        mergedFile.seek(0); // 确保从文件开头读取
        std::cout << mergedFile.get_all() << std::endl;

        File file3 = file1;
        file3.write_data("\nCopy of file1.");
        file3.seek(0); // 确保从文件开头读取
        std::cout << file3.get_all() << std::endl;
    }
    catch (const std::exception &e)
    {
        std::cerr << "Exception: " << e.what() << std::endl;
    }

    return 0;
}
